#include //#include #include #include #include //Pin setup const int DHT_PIN = 2; const int NEO_PIN = 6; const int BUZZER_PIN = 9; const int BTN_PIN = 4; //2.2kohm pullup //Pushbutton bool btn_down_short = false; bool btn_down_long = false; bool btn_ignore = false; bool btn_was_down = false; unsigned long btn_down_started = 0; //Temp and Humidity Sensor SimpleDHT11 dht11; byte temperature = 0; byte humidity = 0; //Neopixel Ring (12 LEDs) Adafruit_NeoPixel strip = Adafruit_NeoPixel(12, 6, NEO_GRB + NEO_KHZ800); //RTC (Real Time Clock Breakout) RTC_DS3231 ds3231; //Keep track of milliseconds between seconds int last_sec_five = 0; unsigned long last_sec_five_millis = 0; //Needed to keep track of datetime editing unsigned long edit_date_blink_millis = 0; int edit_time_hour = 0; int edit_time_min = 0; //RTC time int rtc[7]; //sec,min,hour,dow,day,month,year unsigned long rtc_last_refreshed = 0; //The state to keep track of navigation String state = ""; //The default brightness level of the LEDs int brightness = 20; //1 - 255 int edit_brightness_state = 1; void setup() { Serial.begin(9600); delay(3000); state = "setup_pins"; setupPins(); Serial.println("Pin setup done"); state = "rtc_setup"; setupRtc(); Serial.println("RTC setup done."); setupNeo(); Serial.print("LED brightness defaulted to: "); Serial.println(brightness); state = "led_test"; ledTest(); Serial.println("LED test done."); state = "show_time"; } void loop() { Serial.print(rtc[2]); Serial.print(":"); Serial.print(rtc[1]); Serial.print(":"); Serial.print(rtc[0]); Serial.print(" -- "); Serial.print((int)(((int)temperature * 9)/5) + 32); Serial.print(" -- "); Serial.print(humidity); Serial.print(" -- "); Serial.println(brightness); unsigned long current_millis = millis(); checkButtonState(); //Refresh RTC time buffer every second if(millis() - rtc_last_refreshed > 1000 || rtc_last_refreshed > millis()) { rtc_last_refreshed = millis(); getDateTime(); getDhtData(); } //Keep track of milliseconds between each multiples of 5 seconds if(rtc[0]/5 != last_sec_five) { last_sec_five = rtc[0]/5; last_sec_five_millis = millis(); } if(state == "edit_time") { state = "edit_hour"; } else if(state == "edit_hour") { if(btn_down_long) { state = "edit_minute"; } else { editHour(); } } else if(state == "edit_minute") { if(btn_down_long) { //User just finished editing the time, set the entered time in RTC setDateTime(0, edit_time_min, edit_time_hour, rtc[3], rtc[4], rtc[5], rtc[6]); printRtcToSerial(); state = "show_time"; } else { editMinute(); } } else if(state == "show_temperature") { if(btn_down_short) { state = "show_humidity"; } else if(btn_down_long) { } else { showTemperature(); } } else if(state == "show_humidity") { if(btn_down_short) { state = "show_brightness"; } else if(btn_down_long) { } else { showHumidity(); } } else if(state == "edit_brightness") { if(btn_down_long) { state = "show_brightness"; } else { editBrightness(); } } else if(state == "show_brightness") { if(btn_down_short) { state = "show_time"; } if(btn_down_long) { state = "edit_brightness"; } else { showBrightness(); } } else { if(btn_down_short) { state = "show_temperature"; } else if(btn_down_long) { state = "edit_time"; } else { showTime(rtc[2], rtc[1], rtc[0]); } } } void setupPins() { pinMode(BUZZER_PIN, OUTPUT); pinMode(BTN_PIN, INPUT); } void setupRtc() { if(!ds3231.begin()) { Serial.println("Couldn't find RTC"); while (1); } if(ds3231.lostPower()) { Serial.println("RTC lost power, lets set the time!"); ds3231.adjust(DateTime(F(__DATE__), F(__TIME__))); } getDateTime(); printRtcToSerial(); } void printRtcToSerial() { Serial.print("RTC set to: "); Serial.print(rtc[5]); Serial.print("/"); Serial.print(rtc[4]); Serial.print("/"); Serial.print(rtc[6]); Serial.print(" "); Serial.print(rtc[2]); Serial.print(":"); Serial.print(rtc[1]); Serial.print(":"); Serial.println(rtc[0]); } void setupNeo() { strip.begin(); strip.show(); strip.setBrightness(brightness); } void ledTest() { clearNeo(); strip.setPixelColor(0, 255, 255, 255); strip.show(); delay(1000); for(int p=0; p <= 11; p++) { clearNeo(); strip.setPixelColor(p , 255, 0, 0); strip.show(); delay(50); } for(int p=0; p <= 11; p++) { clearNeo(); strip.setPixelColor(p , 0, 255, 0); strip.show(); delay(50); } for(int p=0; p <= 11; p++) { clearNeo(); strip.setPixelColor(p , 0, 0, 255); strip.show(); delay(50); } } void getDateTime() { DateTime now = ds3231.now(); rtc[0] = now.second(); rtc[1] = now.minute(); rtc[2] = now.hour(); rtc[3] = now.dayOfTheWeek(); rtc[4] = now.day(); rtc[5] = now.month(); rtc[6] = now.year(); } void setDateTime(int sec, int min, int hour, int dow, int day, int month, int year) { ds3231.adjust(DateTime(year, month, day, hour, min, sec)); getDateTime(); edit_time_hour = 0; edit_time_min = 0; } void showTime(int show_hour, int show_minute, int show_second) { int five_millis = millis() - last_sec_five_millis; five_millis = five_millis <= 5000 ? five_millis : 5000; int second_ratio = map(five_millis, 0, 5000, 0, 255); int second = (show_second/5)+1; int minute_ratio = map(((show_minute % 5)*10), 0, 50, 0, 255); int minute = (show_minute/5)+1; int hour_ratio = map(show_minute, 0, 60, 0, 255); int hour = (show_hour > 12 ? show_hour-12 : show_hour); for(int x=0; x < 13; x++) { int r = 0; int g = 0; int b = 0; if(second-1 == x) { g = 255-second_ratio; } if(second == x || (second == 12 && x == 0)) { g = second_ratio; } if(minute-1 == x) { b = 255-minute_ratio; } if(minute == x) { b = minute_ratio; } if(hour-1 == x) { r = 255-hour_ratio; } if(hour == x) { r = hour_ratio; } strip.setPixelColor(x, r, g, b); } strip.show(); delay(40); } void editHour() { if(edit_time_hour == 0) { edit_time_hour = rtc[2]; edit_time_hour = (edit_time_hour > 24 ? edit_time_hour-24 : edit_time_hour); } if(btn_down_short) { edit_time_hour = (edit_time_hour > 23 ? edit_time_hour = 1 : edit_time_hour + 1); } clearNeo(); if(edit_time_hour > 12) { strip.setPixelColor(edit_time_hour-13 , 120, 0, 120); } else { strip.setPixelColor(edit_time_hour-1 , 255, 0, 0); } strip.show(); delay(40); } void editMinute() { if(edit_time_min == 0) { edit_time_min = rtc[1]; } if(btn_down_short) { edit_time_min = (edit_time_min >= 59 ? edit_time_min = 1 : edit_time_min + 1); } int minute_ratio = map(((edit_time_min % 5)*10), 0, 50, 0, 255); int minute = (edit_time_min/5); clearNeo(); strip.setPixelColor(minute-1, 0, 0, 255-minute_ratio); strip.setPixelColor(minute , 0, 0, minute_ratio); strip.show(); delay(40); } void showBrightness() { clearNeo(); strip.setPixelColor(0, 255, 0, 0); strip.setPixelColor(1, 255, 0, 0); strip.setPixelColor(2, 255, 0, 0); strip.setPixelColor(3, 255, 0, 0); strip.setPixelColor(4, 0, 255, 0); strip.setPixelColor(5, 0, 255, 0); strip.setPixelColor(6, 0, 255, 0); strip.setPixelColor(7, 0, 255, 0); strip.setPixelColor(8, 0, 0, 255); strip.setPixelColor(9, 0, 0, 255); strip.setPixelColor(10, 0, 0, 255); strip.setPixelColor(11, 0, 0, 255); strip.show(); delay(100); } void editBrightness() { if(btn_down_short) { brightness = (brightness >= 236 ? brightness = 20 : brightness + 20); strip.setBrightness(brightness); } edit_brightness_state = (edit_brightness_state >= 12 ? edit_brightness_state = 1 : edit_brightness_state + 1); int p = edit_brightness_state; clearNeo(); strip.setPixelColor(0, (p == 1 ? 255 : 50), 0, 0); strip.setPixelColor(1, (p == 2 ? 255 : 50), 0, 0); strip.setPixelColor(2, (p == 3 ? 255 : 50), 0, 0); strip.setPixelColor(3, (p == 4 ? 255 : 50), 0, 0); strip.setPixelColor(4, 0, (p == 5 ? 255 : 50), 0); strip.setPixelColor(5, 0, (p == 6 ? 255 : 50), 0); strip.setPixelColor(6, 0, (p == 7 ? 255 : 50), 0); strip.setPixelColor(7, 0, (p == 8 ? 255 : 50), 0); strip.setPixelColor(8, 0, 0, (p == 9 ? 255 : 50)); strip.setPixelColor(9, 0, 0, (p == 10 ? 255 : 50)); strip.setPixelColor(10, 0, 0, (p == 11 ? 255 : 50)); strip.setPixelColor(11, 0, 0, (p == 12 ? 255 : 50)); strip.show(); delay(50); } void showTemperature() { clearNeo(); for(int x=0; x < 12; x++) { strip.setPixelColor(x, 15, 15, 0); } int temp = (int)(((int)temperature * 9)/5) + 32; if(temp > 0 && temp <= 12) { strip.setPixelColor(temp, 255, 0, 0); } else if(temp > 12 && temp <= 99) { int first_int = nthDigit(temp, 1)-1; int second_int = nthDigit(temp, 2)-1; if(first_int == second_int) { strip.setPixelColor(nthDigit(temp, 1)-1, 255, 0, 255); } else { strip.setPixelColor(nthDigit(temp, 1)-1, 255, 0, 0); strip.setPixelColor(nthDigit(temp, 2)-1, 0, 0, 255); } } strip.show(); delay(40); } void showHumidity() { clearNeo(); for(int x=0; x < 12; x++) { strip.setPixelColor(x, 0, 0, 15); } int hum = (int)humidity; if(hum > 0 && hum <= 12) { strip.setPixelColor(hum, 255, 0, 0); } else if(hum > 12 && hum <= 99) { int first_int = nthDigit(hum, 1)-1; int second_int = nthDigit(hum, 2)-1; if(first_int == second_int) { strip.setPixelColor(first_int, 255, 0, 255); } else { strip.setPixelColor(first_int, 255, 0, 0); strip.setPixelColor(second_int, 0, 0, 255); } } strip.show(); delay(40); } int nthDigit(int x, int n) { if(x <= 0 || x >= 100) { return 0; } if(x > 0 && x < 10) { return x; } if(n == 2) { return x-floor(x/10)*10; } if(n == 1) { return floor(x/10); } } void clearNeo() { strip.setPixelColor(0, 0, 0, 0); strip.setPixelColor(1, 0, 0, 0); strip.setPixelColor(2, 0, 0, 0); strip.setPixelColor(3, 0, 0, 0); strip.setPixelColor(4, 0, 0, 0); strip.setPixelColor(5, 0, 0, 0); strip.setPixelColor(6, 0, 0, 0); strip.setPixelColor(7, 0, 0, 0); strip.setPixelColor(8, 0, 0, 0); strip.setPixelColor(9, 0, 0, 0); strip.setPixelColor(10, 0, 0, 0); strip.setPixelColor(11, 0, 0, 0); } void checkButtonState() { //Is the button being press right now bool btn_is_pressed = digitalRead(BTN_PIN) == LOW ? false : true; //If the button long press was registered in the last loop, stop it in this loop if(btn_down_long) { btn_down_long = false; } //If a long press was registered in the last loop, and user is still pushing, ignore it if(!btn_ignore) { //If the button is being pressed now and was not being pressed before, start counting press time if(btn_is_pressed && !btn_was_down) { btn_down_started = millis(); tone(BUZZER_PIN, 2000); delay(200); noTone(BUZZER_PIN); } //If button is not pressed now and was pressed before, register short press if(!btn_is_pressed && btn_was_down) { btn_down_short = true; } else { btn_down_short = false; } //If button is pressed now and has been pressed for more than 2 sec, register long press if(btn_is_pressed && btn_was_down && (millis() - btn_down_started) > 2000) { btn_down_long = true; //Ignore the button press until the user lets go btn_ignore = true; tone(BUZZER_PIN, 2000); delay(200); noTone(BUZZER_PIN); tone(BUZZER_PIN, 2000); delay(200); noTone(BUZZER_PIN); } else { btn_down_long = false; } } //If the user last did a long press and now they have let go, do not ignore button press anymore if(btn_was_down && !btn_is_pressed) { btn_ignore = false; } //Let this loops button state be known in the next loop btn_was_down = btn_is_pressed; } void getDhtData() { dht11.read(DHT_PIN, &temperature, &humidity, NULL); }